#!/bin/bash

# ThingsBoard PostgreSQL版本备份脚本
# 作者：Vondser
# 版本：1.0
# 功能：备份ThingsBoard的PostgreSQL数据库、配置文件和数据文件（不包含Cassandra）

# 日志配置
LOG_DIR="/var/log/tb-backup"
LOG_FILE="${LOG_DIR}/tb_backup_postgresql_$(date +"%Y-%m-%d").log"
SCRIPT_NAME=$(basename "$0")

# 备份目录和文件名设置
DATE=$(date +"%Y-%m-%d_%H-%M-%S")
BACKUP_BASE_DIR="/backup/thingsboard-postgresql"
BACKUP_DIR="${BACKUP_BASE_DIR}/${DATE}"
FINAL_BACKUP_FILE="${BACKUP_BASE_DIR}/thingsboard_postgres_backup_${DATE}.tar.gz"

# 确保日志目录存在
mkdir -p ${LOG_DIR}

# 日志函数
log_info() {
    local message="[INFO] [$(date +"%Y-%m-%d %H:%M:%S")] [${SCRIPT_NAME}] $1"
    echo -e "\033[0;32m${message}\033[0m" | tee -a ${LOG_FILE}
}

log_warning() {
    local message="[WARNING] [$(date +"%Y-%m-%d %H:%M:%S")] [${SCRIPT_NAME}] $1"
    echo -e "\033[0;33m${message}\033[0m" | tee -a ${LOG_FILE}
}

log_error() {
    local message="[ERROR] [$(date +"%Y-%m-%d %H:%M:%S")] [${SCRIPT_NAME}] $1"
    echo -e "\033[0;31m${message}\033[0m" | tee -a ${LOG_FILE}
}

log_success() {
    local message="[SUCCESS] [$(date +"%Y-%m-%d %H:%M:%S")] [${SCRIPT_NAME}] $1"
    echo -e "\033[0;32m${message}\033[0m" | tee -a ${LOG_FILE}
}

# 记录脚本开始执行
log_info "====== ThingsBoard PostgreSQL版本备份开始 ======"
log_info "备份目录: ${BACKUP_DIR}"
log_info "日志文件: ${LOG_FILE}"

# 检查是否以root用户运行
if [ "$(id -u)" != "0" ]; then
   log_error "此脚本必须以root用户身份运行"
   exit 1
fi

# 创建备份目录
mkdir -p ${BACKUP_DIR}
if [ $? -ne 0 ]; then
    log_error "无法创建备份目录: ${BACKUP_DIR}"
    exit 1
fi
log_info "成功创建备份目录"

# 检查ThingsBoard服务是否在运行
if systemctl is-active --quiet thingsboard; then
    log_info "ThingsBoard服务正在运行"
else
    log_warning "ThingsBoard服务未运行，继续执行备份但可能不完整"
fi

# 1. 备份ThingsBoard配置
log_info "开始备份ThingsBoard配置..."
if [ -d "/etc/thingsboard" ]; then
    tar -czf ${BACKUP_DIR}/tb_config.tar.gz /etc/thingsboard 2>>${LOG_FILE}
    if [ $? -eq 0 ]; then 
        log_success "ThingsBoard配置备份成功"
        # 记录配置文件的基本信息
        find /etc/thingsboard -type f | sort > ${BACKUP_DIR}/tb_config_files_list.txt
        log_info "配置文件列表已保存到 tb_config_files_list.txt"
    else 
        log_error "ThingsBoard配置备份失败"
    fi
else
    log_error "ThingsBoard配置目录不存在: /etc/thingsboard"
fi

# 2. 备份ThingsBoard数据目录
log_info "开始备份ThingsBoard数据..."
if [ -d "/var/lib/thingsboard" ]; then
    tar -czf ${BACKUP_DIR}/tb_data.tar.gz /var/lib/thingsboard 2>>${LOG_FILE}
    if [ $? -eq 0 ]; then 
        log_success "ThingsBoard数据备份成功"
        # 记录数据目录的大小和文件数量
        du -sh /var/lib/thingsboard > ${BACKUP_DIR}/tb_data_size.txt
        find /var/lib/thingsboard -type f | wc -l >> ${BACKUP_DIR}/tb_data_size.txt
        log_info "数据目录大小信息已保存到 tb_data_size.txt"
    else 
        log_error "ThingsBoard数据备份失败"
    fi
else
    log_error "ThingsBoard数据目录不存在: /var/lib/thingsboard"
fi

# 3. 备份PostgreSQL数据库
log_info "开始备份PostgreSQL数据库..."
# 检查PostgreSQL服务是否在运行
if systemctl is-active --quiet postgresql; then
    log_info "PostgreSQL服务正在运行"
    # 检查thingsboard数据库是否存在
    if sudo -u postgres psql -lqt | cut -d \| -f 1 | grep -qw thingsboard; then
        log_info "PostgreSQL中的thingsboard数据库存在，开始备份..."
        
        # 记录PostgreSQL数据库大小
        log_info "记录PostgreSQL数据库大小信息..."
        sudo -u postgres psql -c "SELECT pg_size_pretty(pg_database_size('thingsboard'))" > ${BACKUP_DIR}/postgres_db_size.txt
        
        # 记录PostgreSQL表结构
        log_info "记录PostgreSQL表结构信息..."
        sudo -u postgres pg_dump -s thingsboard > ${BACKUP_DIR}/postgres_schema.sql
        
        # 记录PostgreSQL用户和权限
        log_info "记录PostgreSQL用户和权限信息..."
        sudo -u postgres pg_dumpall --globals-only > ${BACKUP_DIR}/postgres_globals.sql
        
        # 执行完整备份
        log_info "执行PostgreSQL完整备份..."
        sudo -u postgres pg_dump -Fc thingsboard > ${BACKUP_DIR}/tb_postgres.dump 2>>${LOG_FILE}
        
        if [ $? -eq 0 ]; then 
            log_success "PostgreSQL备份成功"
            # 计算备份文件大小
            POSTGRES_BACKUP_SIZE=$(du -h ${BACKUP_DIR}/tb_postgres.dump | cut -f1)
            log_info "PostgreSQL备份文件大小: ${POSTGRES_BACKUP_SIZE}"
            
            # 生成SQL文本格式备份，便于查看和修改
            log_info "生成SQL文本格式备份..."
            sudo -u postgres pg_dump thingsboard > ${BACKUP_DIR}/tb_postgres.sql 2>>${LOG_FILE}
            if [ $? -eq 0 ]; then
                log_success "PostgreSQL SQL文本备份成功"
            else
                log_warning "PostgreSQL SQL文本备份失败，但不影响使用自定义格式备份进行还原"
            fi
        else 
            log_error "PostgreSQL备份失败"
        fi
    else
        log_error "PostgreSQL中的thingsboard数据库不存在"
    fi
else
    log_error "PostgreSQL服务未运行，无法备份PostgreSQL数据库"
fi

# 4. 备份数据库连接配置
log_info "备份数据库连接配置..."
if [ -f "/etc/thingsboard/conf/thingsboard.conf" ]; then
    grep -E 'SPRING_DATASOURCE|POSTGRES|SQL|DATABASE' /etc/thingsboard/conf/thingsboard.conf > ${BACKUP_DIR}/database_config.txt
    if [ $? -eq 0 ]; then
        log_success "数据库连接配置备份成功"
    else
        log_warning "没有找到数据库连接配置或提取失败"
    fi
fi

# 5. 备份元数据信息
log_info "备份系统信息..."
# 软件包版本信息
log_info "记录相关软件包版本信息..."
dpkg -l | grep -E 'thingsboard|postgresql' > ${BACKUP_DIR}/package_versions.txt
# 系统信息
log_info "记录系统信息..."
uname -a > ${BACKUP_DIR}/system_info.txt
# Java版本
log_info "记录Java版本信息..."
java -version > ${BACKUP_DIR}/java_version.txt 2>&1
# 磁盘使用情况
log_info "记录磁盘使用情况..."
df -h > ${BACKUP_DIR}/disk_usage.txt
# ThingsBoard状态
log_info "记录ThingsBoard服务状态..."
systemctl status thingsboard > ${BACKUP_DIR}/thingsboard_status.txt 2>&1
# PostgreSQL版本和配置
log_info "记录PostgreSQL版本和配置..."
sudo -u postgres psql -c "SELECT version();" > ${BACKUP_DIR}/postgres_version.txt
pg_config --version >> ${BACKUP_DIR}/postgres_version.txt 2>&1
log_success "系统信息备份完成"

# 6. 创建备份说明文件
log_info "创建备份说明文件..."
cat > ${BACKUP_DIR}/README.txt << EOF
ThingsBoard PostgreSQL版本备份文件

备份日期: $(date +"%Y-%m-%d %H:%M:%S")
系统: $(uname -a)
ThingsBoard版本: $(grep -E 'thingsboard' ${BACKUP_DIR}/package_versions.txt | head -1)
PostgreSQL版本: $(cat ${BACKUP_DIR}/postgres_version.txt | head -1)

备份内容:
- PostgreSQL数据库备份 (tb_postgres.dump, tb_postgres.sql)
- ThingsBoard配置文件 (tb_config.tar.gz)
- ThingsBoard数据文件 (tb_data.tar.gz)
- 系统信息和元数据

还原方法:
使用restore_script_postgresql.sh脚本进行还原。
示例: sudo ./restore_script_postgresql.sh ${FINAL_BACKUP_FILE}

注意: 此备份不包含Cassandra数据库，仅包含PostgreSQL数据库版本的ThingsBoard备份。
EOF
log_success "备份说明文件创建成功"

# 7. 压缩整个备份目录
log_info "压缩备份文件..."
cd ${BACKUP_BASE_DIR}/
tar -czf thingsboard_postgres_backup_${DATE}.tar.gz ${DATE}/ 2>>${LOG_FILE}
if [ $? -eq 0 ]; then 
    log_success "备份文件压缩成功: ${FINAL_BACKUP_FILE}"
    # 记录最终备份文件的大小
    BACKUP_SIZE=$(du -h ${FINAL_BACKUP_FILE} | cut -f1)
    log_info "最终备份文件大小: ${BACKUP_SIZE}"
    
    # 计算备份文件的MD5校验和
    log_info "计算备份文件MD5校验和..."
    md5sum ${FINAL_BACKUP_FILE} > ${FINAL_BACKUP_FILE}.md5
    log_success "MD5校验和已保存到 ${FINAL_BACKUP_FILE}.md5"
    
    # 可选：移除原始备份文件夹以节省空间
    log_info "清理临时备份目录..."
    rm -rf ${DATE}/
    log_success "临时备份目录清理完成"
else 
    log_error "备份文件压缩失败"
fi

# 8. 清理旧备份（保留30天）
log_info "清理30天前的旧备份..."
find ${BACKUP_BASE_DIR}/ -name "thingsboard_postgres_backup_*" -type f -mtime +30 -delete
log_success "旧备份清理完成"

# 9. 备份完成，统计信息
BACKUP_END_TIME=$(date +"%Y-%m-%d %H:%M:%S")
BACKUP_DURATION=$(($(date +%s) - $(date -d "$(head -1 ${LOG_FILE} | grep -o '\[INFO\] \[[^]]*\]' | cut -d'[' -f3 | tr -d ']')" +%s)))
DURATION_MINS=$((BACKUP_DURATION / 60))
DURATION_SECS=$((BACKUP_DURATION % 60))

log_info "====== ThingsBoard PostgreSQL版本备份完成 ======"
log_info "备份开始时间: $(head -1 ${LOG_FILE} | grep -o '\[INFO\] \[[^]]*\]' | cut -d'[' -f3 | tr -d ']')"
log_info "备份结束时间: ${BACKUP_END_TIME}"
log_info "备份总耗时: ${DURATION_MINS}分${DURATION_SECS}秒"
log_info "备份文件路径: ${FINAL_BACKUP_FILE}"
log_info "备份文件大小: ${BACKUP_SIZE}"

# 备份结果检查
if [ -f "${FINAL_BACKUP_FILE}" ] && [ -f "${FINAL_BACKUP_FILE}.md5" ]; then
    log_success "备份成功完成！"
    exit 0
else
    log_error "备份过程中出现问题，请检查日志"
    exit 1
fi 